use std::{fs, process::exit};
use common::{command::Command, usage::Usage};
use std::path::PathBuf;

/// 控制字段
/// # Control Field
/// 控制 `ls` 命令的输出等信息
#[derive(Debug, Clone, Copy)]
enum ControlField {
	None = 0,
	/// 输出所有文件，不过滤
	FieldAll = 1 << 0,
	/// 帮助
	FieldHelp = 1 << 1,
}

/// ls 命令的结构
/// # List System
/// - `cmd_set`: 命令集合，包括是那个命令以及命令的参数(ls -al)
/// - `current_dir`: 当前程序的工作目录
#[derive(Debug, Clone)]
pub struct ListSystem {
	/// 命令集合，封装命令名称和参数。
	cmd_set: Command,
	/// 当前的工作目录。
	current_dir: String,
	/// 控制字段
	field: u64,
}

impl Usage for ListSystem {
	fn usage(&self) {
		println!("Usage: ls [OPTION]... [FILE]...");
		println!("List information about the FILEs (the current directory by default).");
		println!("Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.");
		println!("\nMandatory arguments to long options are mandatory for short options too.");
		println!(" -a, --all          输出指定目录下的所有文件");
		println!("     --help         输出使用帮助文档")
	}
}

impl ListSystem {
	pub fn new(cmd_set: Command, current_dir: String) -> Self {
		Self { 
			cmd_set, 
			current_dir,
			field: 0,
		}
	}

	pub fn run(&mut self) -> bool {
		let list_item = self.parse_args();
		
		for ctl_field in list_item.list_ctl_field {
			match ctl_field.trim() {
				"all" => { self.field |= ControlField::FieldAll as u64; }
				"a" => { self.field |= ControlField::FieldAll as u64; }
				"help" => { self.field |= ControlField::FieldHelp as u64 }
				_ => { 
					eprintln!("ls: invalid option -- '{}'", &ctl_field);
					eprintln!("Try 'ls --help' for more information.");
					exit(-1)
				}
			}
		}
		
		if (self.field & (ControlField::FieldHelp as u64)) != 0 {
			self.usage();
		}
		else {
			if list_item.list_file_or_dir.is_empty() {
				// 获取当前目录
				self.from_dir_get_file_list(&self.current_dir);
			} else {

			}
		}

		true
	}

	fn parse_args(&self) -> ListItem {
		let mut list_item = ListItem::new();

		for cmd in self.cmd_set.args.iter() {
			if cmd.starts_with("--") {
				if let Some(name) = cmd.strip_prefix("--") {
					list_item.list_ctl_field.push(name.to_string());
				}
			} else if cmd.starts_with("-") {
				if let Some(name) = cmd.strip_prefix("-") {
					for c in name.chars() {
						list_item.list_ctl_field.push(c.to_string());
					}
				}
			} else {
				list_item.list_file_or_dir.push(cmd.to_string());
			}
		}

		list_item
	}

	fn from_dir_get_file_list(&self, path: &String) -> FileList {
		let mut file_list = FileList::new();

		let entries = match fs::read_dir(&path) {
        	Ok(entries) => entries,
			Err(e) => {
				eprintln!("读取目录失败: {}", e);
				exit(-1);
			}
		};

		for entry in entries.flatten() {
			let path_buf: PathBuf = entry.path();
			let name = entry
				.file_name()
				.to_string_lossy()
				.to_string();
			let is_dir = path_buf.is_dir();

			let mut file_item = FileItem::new();
			file_item.name = name;
			file_item.file_type = if is_dir { FileType::TypeDir } else { FileType::TypeFile };

			file_list.push_back(file_item);
		}

		println!("file list: {:?}", file_list);

		file_list
	}
}

#[derive(Debug)]
struct ListItem {
	pub list_ctl_field: Vec<String>,
	pub list_file_or_dir: Vec<String>,
}

impl ListItem {
	pub fn new() -> Self {
		Self { list_ctl_field: Vec::new(), list_file_or_dir: Vec::new() }
	}
}

#[derive(Debug)]
enum FileType {
	/// 文件
	TypeFile,
	/// 目录
	TypeDir,
}

#[derive(Debug)]
struct FileItem {
	/// 文件名称
	pub name: String,
	/// 文件类型
	pub file_type: FileType,
	/// 文件权限
	pub permission: u32,
	/// 文件大小
	pub file_size: u32,
	/// 文件所有人（持有人）
	pub file_owner: String,
	/// 文件所属组
	pub file_group: String,
}

impl FileItem {
	pub fn new() -> Self {
		Self { 
			name: String::new(), 
			file_type: FileType::TypeFile, 
			permission: 0, 
			file_size: 0, 
			file_owner: String::new(), 
			file_group: String::new() 
		}
	}
}

#[derive(Debug)]
struct FileList {
	file_list: Vec<FileItem>,
}

impl FileList {
	pub fn new() -> Self {
		Self { file_list: Vec::new() }
	}

	pub fn push_back(&mut self, item: FileItem) {
		self.file_list.push(item);
	}

	pub fn get_file_list(&self) -> &Vec<FileItem> {
		&self.file_list
	}
}